import java.io.Serializable;


public class FreqNote implements Serializable{
	
	/**
	 * This class represent a note and it's frequency.
	 * A note has an octave, and its place in the octave.
	 * The class print for every note its frequency, and can present data about the note.
	 * An item in the class can also be the middle point between two notes.
	 */
	private static final long serialVersionUID = 1L;
	
	private int A; //the A of the octave
	private int Oct; //the number of the octave
	private int halfTune; //the distance of the note from the A of the octave
	private boolean quaterTune; //does it the middle point between two notes (true if its not a note)
	
	public FreqNote() {
		this.Oct = 1;
		this.halfTune = 1;
		this.A = (int) Note.lowA;
		this.quaterTune = false;
	}
	
	public FreqNote(int A) {
		if (A == 0) {
			this.A = 0;
			this.halfTune = 0;
			this.Oct = 0;
			this.quaterTune = false;
		}
		else {
			this.A = A;
			this.halfTune = 1;
			this.Oct = getAOct(A);
			this.quaterTune = false;
		}

	}
	
	public FreqNote(int A, int tunes) {
		this.A = A;
		this.halfTune = tunes+1;
		this.Oct = getAOct(A);
		this.quaterTune = false;
	}
	
	public FreqNote(FreqNote note) {
		this.A = note.getA();
		this.halfTune = note.getTune();
		this.Oct = note.getFreqNoteOct();
		this.quaterTune = note.isQuaterTune();
	}
	
	public void setA(int a) {
		A = a;
	}
	public int getA() {
		return A;
	}
	public void setFreqNoteOct(int oct) {
		Oct = oct;
	}
	public int getFreqNoteOct() {
		return Oct;
	}
	public void setTune(int halfTune) {
		this.halfTune = halfTune;
	}
	public int getTune() {
		return halfTune;
	}
	public boolean isQuaterTune() {
		return this.quaterTune;
	}
	
	/*
	 * print the name of the note,
	 * by its distance from A.
	 */
	public String getNote(){
		if (this.halfTune == 0)
			return "Silence";
		else if (this.halfTune == 1)
			return "A";
		else if (this.halfTune == 2)
			return "A#";
		else if (this.halfTune == 3)
			return "B";
		else if (this.halfTune == 4)
			return "C";
		else if (this.halfTune == 5)
			return "C#";
		else if (this.halfTune == 6)
			return "D";
		else if (this.halfTune == 7)
			return "D#";
		else if (this.halfTune == 8)
			return "E";
		else if (this.halfTune == 9)
			return "F";
		else if (this.halfTune == 10)
			return "F#";
		else if (this.halfTune == 11)
			return "G";
		else
			return "G#";
	}
	
	/*
	 * Calculate the frequency of the note.
	 * From the frequency of A, it calculate the frequency of the note by
	 * multiply by 2^(1/12) for every half tone, and 2^(1/24) for every
	 * quarter tone (half point between two notes)
	 */
	public double getFreqOfNote(){
		double value = (double) this.A;
		for (int i=1; i<this.halfTune; i++) {
			value *= Note.root12of2;
		}
		if (this.quaterTune) {
			value *= Note.root24of2;
		}
		return value;
	}
	
	/*
	 * print the frequency(!) of the note.
	 */
	public String toString(){
		String st = "";
		st += this.getFreqOfNote();
		return st;
	}
	
	/*
	 * Increase the note by half tones, making it the next note.
	 */
	public void increaseByHalfTune() {
		this.halfTune++;
		if (this.halfTune == 13) {
			this.halfTune = 1;
			this.A *=2;
			this.Oct++;
		}
	}

	/*
	 * Increase the note by n half tones.
	 */
	public void increaseBy(int n) {
		this.halfTune+=n;
		while (this.halfTune >= 13) {
			this.halfTune -= 12;
			this.A *=2;
			this.Oct++;
		}
	}
	
	/*
	 * Increase the note by quarter tone. making it a middle point (or making a middle point into a note).
	 */
	public void increaseByQuaterTune(){
		if(this.quaterTune){
			this.increaseByHalfTune();
		}
		this.quaterTune = !this.quaterTune;
	}
	
	/*
	 * Decrease the note by quarter tone. making it a middle point (or making a middle point into a note).
	 */
	public void decreaseByQuaterTune(){
		if(!this.quaterTune){
			this.decreaseByHalfTune();
		}
		this.quaterTune = !this.quaterTune;
	}
	
	/*
	 * Decrease the note by half tones, making it the former note.
	 */
	private void decreaseByHalfTune() {
		if (!this.isSilence()) {
			this.halfTune--;
			if (this.halfTune == 0) {
				this.halfTune = 13;
				this.A /= 2;
				this.Oct--;
			}
		}
		
	}

	public boolean IsEqual(FreqNote note) {
		if (this.A == note.getA() && this.halfTune == note.getTune() &&
				this.quaterTune == note.isQuaterTune() && this.Oct == note.getFreqNoteOct()) {
			return true;
		}
		return false;
	}
	
	/*
	 * Checks if the note is a silence or a note with frequency.
	 */
	public boolean isSilence(){
		if (this.halfTune == 0)
			return true;
		return false;
	}
	
	public boolean isLegalNote(){
		if (this.halfTune < 13 && this.isLegalA() && this.Oct > 0)
			return true;
		return false;
	}

	/*
	 * Checks if the note is in a supported octave (an octave we use).
	 */
	private boolean isLegalA() {
		if (this.A >= Note.lowA && this.A <= Note.highA)
			return true;
		return false;
	}
	
	/*
	 * get the number of the octave
	 * (where the octave of the lowest A is 1).
	 * illegal octave is 0.
	 */
	public static int getAOct(int A) {
		if (A < Note.lowA || A > Note.highA)
			return 0;
		int counter = 1;
		while (A!=Note.lowA) {
			A/=2;
			counter++;
		}
		return counter;
	}

}
